package com.boe.csb.core.common.utils;

import com.google.common.io.CharStreams;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.apache.http.Header;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.client.ResponseHandler;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.client.methods.HttpRequestBase;
import org.apache.http.client.utils.URIBuilder;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;

/**
 * HttpUtils 工具类
 * Created by tianjin.lp on 16/9/3.
 */
@Component
@Scope("singleton")
public class HttpUtils {

    private static final Logger LOGGER = LoggerFactory.getLogger(HttpUtils.class);
    private final int IO_EXCEPTION_CODE = -500;

    private static CloseableHttpClient httpClient;
    //连接超时时间为30s
    private int connectionTimeout = 30000;
    //读取超时时间为20s
    private int socketTimeout = 20000;
    private int MAX_TOTAL = 3000;
    private int MAX_PER_ROUTE = 1000;
    //设置从链接池中获取连接时间为无限大
    private int CONNECTION_REQUEST_TIMEOUT = 0;

    @PostConstruct
    public void init() {
        //RequestConfig.custom().setConnectionRequestTimeout() 默认为无限大，就是从连接池等待连接的时间为无限大
        RequestConfig config = RequestConfig.custom().setConnectTimeout(connectionTimeout).
                setConnectionRequestTimeout(CONNECTION_REQUEST_TIMEOUT).setSocketTimeout(socketTimeout).build();
        PoolingHttpClientConnectionManager pccm = new PoolingHttpClientConnectionManager();
        pccm.setMaxTotal(MAX_TOTAL);
        pccm.setDefaultMaxPerRoute(MAX_PER_ROUTE);
        httpClient = HttpClients.custom().setConnectionManager(pccm).setDefaultRequestConfig(config).build();
    }

    public void shutdown() {
        if (httpClient != null) {
            try {
                httpClient.close();
            } catch (IOException ignored) {}
        }
    }

    public HttpResult doGetString(String url,String cookie) {
        HttpGet httpget = null;
        try {
            httpget = new HttpGet(url);
            HttpResultResponseHandler sph = new HttpResultResponseHandler();
            httpget.setHeader("Cookie", cookie);
            return httpClient.execute(httpget, sph);
        } catch (Exception e) {
            LOGGER.error("Http execute error when get " + url, e);
            if (httpget != null) {
                httpget.abort();
            }
            return failHttp(e.getMessage());
        }
    }

    public HttpResult doGetString(String url, Map<String ,String> params) {
        try {
            URIBuilder uriBuilder = new URIBuilder(url);
            for (Map.Entry<String, String> entry : params.entrySet()) {
                uriBuilder.addParameter(entry.getKey(), entry.getValue());
            }
            HttpGet httpget = new HttpGet(uriBuilder.build());
            httpget.addHeader("contentEncoding", "UTF-8");
            return doExecuteHttpRqeuestBase(httpget);
        } catch (Exception e) {
            LOGGER.error("Error when doGetString : " + url + ", error stack=" + ExceptionUtils.getRootCauseMessage(e));
            return failHttp(e.getMessage());
        }
    }

    public HttpResult doPostWithJsonString(String url, String jsonString) {
        // 创建httppost
        HttpPost httpPost = new HttpPost(url);

        // 设置参数
        RequestConfig.Builder customReqConf = RequestConfig.custom();
        customReqConf.setConnectTimeout(connectionTimeout);
        customReqConf.setSocketTimeout(socketTimeout);
        httpPost.setConfig(customReqConf.build());

        StringEntity entity = new StringEntity(jsonString, "UTF-8");//解决中文乱码问题
        entity.setContentEncoding("UTF-8");
//        entity.setContentType("application/x-www-form-urlencoded");
        entity.setContentType("application/json;charset=UTF-8");
        httpPost.setEntity(entity);
        return doExecuteHttpRqeuestBase(httpPost);
    }

    public HttpResult doExecuteHttpRqeuestBase(HttpRequestBase httpRequestBase) {
        try {
            HttpResultResponseHandler sph = new HttpResultResponseHandler();
            return httpClient.execute(httpRequestBase, sph);
        } catch (Exception e) {
            LOGGER.error("Error when " + httpRequestBase.getMethod() + " : " + httpRequestBase.getURI() + " error stack=" + ExceptionUtils.getRootCauseMessage(e));
            return failHttp(e.getMessage());
        }  finally {
            if (httpRequestBase != null) {
                httpRequestBase.abort();
            }
        }
    }


    private class HttpResultResponseHandler implements ResponseHandler<HttpResult> {
        public HttpResult handleResponse(HttpResponse response) throws IOException {
            HttpResult result = new HttpResult();
            HttpEntity entity = response.getEntity();
            Header[] headers = response.getAllHeaders();
            if (isNotEmpty(headers)) {
                HashMap<String, String> headerMap = new HashMap<String, String>();
                for (Header h : headers) {
                    headerMap.put(h.getName(), h.getValue());
                }
            }

            InputStream i = entity.getContent();
            String res = CharStreams.toString(new InputStreamReader(i, "UTF-8"));
            //String res = EntityUtils.toString(entity);
            result.setCode(response.getStatusLine().getStatusCode());
            result.setBody(res);

            return result;
        }
    }

    private boolean isNotEmpty(Object[] array) {
        return array != null && array.length > 0;
    }

    private HttpResult failHttp(String message) {
        HttpResult result = new HttpResult();
        result.setCode(IO_EXCEPTION_CODE);
        result.setBody(message);
        return result;
    }

    public class HttpResult {
        private String body;
        private Map<String, String> header;
        private int code;

        public String getBody() {
            return body;
        }

        public void setBody(String body) {
            this.body = body;
        }

        public Map<String, String> getHeader() {
            return header;
        }

        public void setHeader(Map<String, String> header) {
            this.header = header;
        }

        public int getCode() {
            return code;
        }

        public void setCode(int code) {
            this.code = code;
        }

        public boolean is200() {
            return this.code == 200;
        }

        public boolean isNot200() {
            return !this.is200();
        }

        public boolean isIOException() {
            return this.code == IO_EXCEPTION_CODE;
        }
    }

    public int getConnectionTimeout() {
        return connectionTimeout;
    }

    public void setConnectionTimeout(int connectionTimeout) {
        this.connectionTimeout = connectionTimeout;
    }

    public int getSocketTimeout() {
        return socketTimeout;
    }

    public void setSocketTimeout(int socketTimeout) {
        this.socketTimeout = socketTimeout;
    }

    public void setMAX_PER_ROUTE(int MAX_PER_ROUTE) {
        this.MAX_PER_ROUTE = MAX_PER_ROUTE;
    }

    public void setMAX_TOTAL(int MAX_TOTAL) {
        this.MAX_TOTAL = MAX_TOTAL;
    }

    public void setCONNECTION_REQUEST_TIMEOUT(int CONNECTION_REQUEST_TIMEOUT) {
        this.CONNECTION_REQUEST_TIMEOUT = CONNECTION_REQUEST_TIMEOUT;
    }

}
